"""
AI智能体数据库模型
"""

import json
from datetime import datetime
from typing import Optional, List, Dict, Any

from sqlalchemy import String, Text, DateTime, ForeignKey, JSON, SmallInteger
from sqlalchemy.orm import relationship, Mapped, mapped_column
from sqlalchemy.sql import func

from config.database import Base


class AIWebAgentModel(Base):
    """AI智能体数据库模型"""
    __tablename__ = "ai_web_agent"

    # 主键和基本字段
    agent_id: Mapped[str] = mapped_column(String(36), primary_key=True, comment="智能体唯一标识，UUID")
    scene_id: Mapped[str] = mapped_column(
        String(36),
        ForeignKey("ai_web_scene.scene_id"),
        nullable=False,
        comment="所属场景ID"
    )
    tenant_id: Mapped[str] = mapped_column(String(36), nullable=False, default="default", comment="租户ID")

    # 核心配置字段
    agent_code: Mapped[str] = mapped_column(Text, nullable=False, comment="智能体核心逻辑代码")
    agent_name: Mapped[str] = mapped_column(String(100), nullable=False, default="", comment="智能体名称")
    sys_prompt: Mapped[str] = mapped_column(Text, nullable=False, comment="系统提示词")
    llm_code: Mapped[str] = mapped_column(String(255), nullable=False, comment="大模型代码，如gpt-4-turbo")
    embedding_code: Mapped[str] = mapped_column(String(255), nullable=False,
                                                comment="向量模型代码，如text-embedding-3-large")

    # JSON配置字段
    tools_list: Mapped[str] = mapped_column(JSON, nullable=False, default="[]", comment="工具配置列表")
    mcp_list: Mapped[str] = mapped_column(JSON, nullable=False, default="[]", comment="多轮对话策略配置")
    rag_list: Mapped[str] = mapped_column(JSON, nullable=False, default="[]", comment="检索增强配置")

    # 状态和版本
    status: Mapped[int] = mapped_column(
        SmallInteger,
        nullable=False,
        default=0,
        comment="状态：0-停用，1-启用，2-训练中"
    )
    version: Mapped[str] = mapped_column(String(20), nullable=False, default="1.0.0", comment="版本号")

    # 软删除标记
    is_deleted: Mapped[int] = mapped_column(SmallInteger, nullable=False, default=0,
                                            comment="删除标记：0-未删除,1-已删除")

    # 审计字段
    created_by: Mapped[str] = mapped_column(String(50), nullable=False, comment="创建者")
    created_at: Mapped[datetime] = mapped_column(
        DateTime,
        nullable=False,
        default=func.now(),
        comment="创建时间"
    )
    updated_by: Mapped[Optional[str]] = mapped_column(String(50), nullable=True, comment="更新者")
    updated_at: Mapped[Optional[datetime]] = mapped_column(
        DateTime,
        nullable=True,
        onupdate=func.now(),
        comment="更新时间"
    )

    # 关系定义
    scene: Mapped["AIWebSceneModel"] = relationship(
        "AIWebSceneModel",
        back_populates="agents"
    )
    memories: Mapped[List["AIWebMemoryHisModel"]] = relationship(
        "AIWebMemoryHisModel",
        back_populates="agent",
        cascade="all, delete-orphan"
    )

    # 索引和约束
    __table_args__ = (
        {"comment": "AI智能体表"}
    )

    def __repr__(self):
        return f"<AIWebAgentModel(agent_id='{self.agent_id}', agent_name='{self.agent_name}', status={self.status})>"

    def to_dict(self) -> dict:
        """转换为字典"""
        return {
            "agent_id": self.agent_id,
            "scene_id": self.scene_id,
            "tenant_id": self.tenant_id,
            "agent_code": self.agent_code,
            "agent_name": self.agent_name,
            "sys_prompt": self.sys_prompt,
            "llm_code": self.llm_code,
            "embedding_code": self.embedding_code,
            "tools_list": self.get_tools_list(),
            "mcp_list": self.get_mcp_list(),
            "rag_list": self.get_rag_list(),
            "status": self.status,
            "version": self.version,
            "is_deleted": self.is_deleted,
            "created_by": self.created_by,
            "created_at": self.created_at.isoformat() if self.created_at else None,
            "updated_by": self.updated_by,
            "updated_at": self.updated_at.isoformat() if self.updated_at else None
        }

    def get_tools_list(self) -> List[Dict[str, Any]]:
        """获取工具配置列表"""
        if isinstance(self.tools_list, str):
            try:
                return json.loads(self.tools_list)
            except (json.JSONDecodeError, TypeError):
                return []
        return self.tools_list or []

    def set_tools_list(self, tools: List[Dict[str, Any]]) -> None:
        """设置工具配置列表"""
        self.tools_list = json.dumps(tools, ensure_ascii=False) if tools else "[]"

    def get_mcp_list(self) -> List[Dict[str, Any]]:
        """获取多轮对话策略配置"""
        if isinstance(self.mcp_list, str):
            try:
                return json.loads(self.mcp_list)
            except (json.JSONDecodeError, TypeError):
                return []
        return self.mcp_list or []

    def set_mcp_list(self, mcp: List[Dict[str, Any]]) -> None:
        """设置多轮对话策略配置"""
        self.mcp_list = json.dumps(mcp, ensure_ascii=False) if mcp else "[]"

    def get_rag_list(self) -> List[Dict[str, Any]]:
        """获取检索增强配置"""
        if isinstance(self.rag_list, str):
            try:
                return json.loads(self.rag_list)
            except (json.JSONDecodeError, TypeError):
                return []
        return self.rag_list or []

    def set_rag_list(self, rag: List[Dict[str, Any]]) -> None:
        """设置检索增强配置"""
        self.rag_list = json.dumps(rag, ensure_ascii=False) if rag else "[]"

    def is_active(self) -> bool:
        """判断智能体是否处于启用状态"""
        return self.status == 1 and self.is_deleted == 0

    def is_training(self) -> bool:
        """判断智能体是否处于训练状态"""
        return self.status == 2 and self.is_deleted == 0

    def is_disabled(self) -> bool:
        """判断智能体是否处于停用状态"""
        return self.status == 0

    def soft_delete(self, deleted_by: str) -> None:
        """软删除智能体"""
        self.is_deleted = 1
        self.updated_by = deleted_by
        self.updated_at = datetime.now()

    def restore(self, restored_by: str) -> None:
        """恢复已删除的智能体"""
        self.is_deleted = 0
        self.updated_by = restored_by
        self.updated_at = datetime.now()

    def update_status(self, new_status: int, updated_by: str) -> None:
        """更新智能体状态"""
        # 验证status值
        if not isinstance(new_status, int):
            # 如果传入的是字符串，尝试转换
            if isinstance(new_status, str):
                try:
                    new_status = int(new_status)
                except ValueError:
                    raise ValueError(f"无效的状态值: {new_status}，必须是 0, 1, 2 中的一个")
            else:
                raise ValueError(f"状态值必须是整数，当前类型: {type(new_status)}")

        if new_status not in [0, 1, 2]:
            raise ValueError(f"无效的状态值: {new_status}，必须是 0, 1, 2 中的一个")

        self.status = new_status
        self.updated_by = updated_by
        self.updated_at = datetime.now()

    def update_version(self, new_version: str, updated_by: str) -> None:
        """更新智能体版本"""
        import re
        if not re.match(r'^[0-9]+(\.[0-9]+)*$', new_version):
            raise ValueError('版本号格式不正确，应为数字和点的组合，如1.0.0')

        self.version = new_version
        self.updated_by = updated_by
        self.updated_at = datetime.now()

    def validate_version_format(self, version: str) -> bool:
        """验证版本号格式"""
        import re
        return bool(re.match(r'^[0-9]+(\.[0-9]+)*$', version))

    def get_config_summary(self) -> Dict[str, Any]:
        """获取配置摘要信息"""
        return {
            "llm_code": self.llm_code,
            "embedding_code": self.embedding_code,
            "tools_count": len(self.get_tools_list()),
            "mcp_count": len(self.get_mcp_list()),
            "rag_count": len(self.get_rag_list()),
            "version": self.version,
            "status": self.status
        }

    def clone_config(self) -> Dict[str, Any]:
        """克隆配置信息（用于创建新智能体）"""
        return {
            "agent_code": self.agent_code,
            "sys_prompt": self.sys_prompt,
            "llm_code": self.llm_code,
            "embedding_code": self.embedding_code,
            "tools_list": self.get_tools_list(),
            "mcp_list": self.get_mcp_list(),
            "rag_list": self.get_rag_list()
        }
